This section contains some routines that simplify and enhance the programming experience. Some routines were developed specifically to replace similar parts of the Macintosh’s toolbox by providing simpler or more useful counterparts, such as Tools Plus’s Dynamic Alerts. Other routines were written to mimic existing Macintosh user-interface features to which programmers do not have access, such as the “zoom lines” that are seen when the Finder opens a document, or the standard Macintosh thermometer that indicates an application’s progress. And yet other routines are included because they were needed for the internal working of Tools Plus, and we thought they would be useful for other programmers, such as displaying icon families.
As Tools Plus evolves, we will undoubtedly get feedback from developers (such as yourself) to create additional routines and to add more functionality to the package. This section will definitely expand in future versions of Tools Plus.
pascal int AlertBox (int theIcon Str255 AlertText, long AlertCode);
function AlertBox(theIcon: INTEGER; AlertText: STRING;
AlertCode: LONGINT): INTEGER;
What are Dynamic Alerts?
````````````````````````
Dynamic Alerts are very similar to the Macintosh’s alerts, only they are much better in most situations. They automatically change size and shape to accommodate the text that is displayed in them, and they are always centered on the main monitor. It’s like having hundreds of custom alerts available, without having to design any of them!
When a Dynamic Alert is displayed, it optionally beeps the user and the cursor is changed to the Macintosh arrow. The alert box is automatically sized to accommodate the text specified by your application, and it is centered on the main monitor to be aesthetically pleasing. An icon can optionally be displayed in the top left corner of the alert. Your application specifies the combinations of buttons that appear at the bottom of the alert.
The AlertBox function automatically polls for mouse clicks and typing events. When the user clicks one of the buttons, or types Return or Enter to activate a default button, the alert box disappears and control is returned to your application. The function returns the value of the button that was selected by the user.
Icons
`````
TheIcon is the icon ID that is displayed in the alert. If the icon ID you specify does not exists, then the noteIcon is displayed in its place. Your application can specify any icon it wants, providing the icon resource exists in either the System file or your application. You can create your own icons with a resource editor such as Apple’s ResEdit and use them in alert boxes.
When Tools Plus draws the icon in the Dynamic Alert, it does so by accessing an icon family and by being sensitive to the settings of the monitor on which the icon is being displayed. This means that it displays the best available icon (cicn, icl8, icl4, ICN#, or ICON resource) for the target monitor. For more details, see the DrawIcon procedure which is used by AlertBox to draw the icon.
When you specify an icon, be aware that the System file includes 3 icons that are ready for your use. These are the “stop”, “note”, and “caution” icons.
CONST {Icon IDs for alert icons }
NoIcon =-32768 {no icon displayed in alert box }
stopIcon =0; {stopIcon will automatically access }
noteIcon =1; { ID=3 in system files version 5 or 6.}
cautionIcon=2; { }
If your application is running under System 5 or System 6, the constant stopIcon will try to get an icon that does not exist in the System file (ICON ID=0). In this case, AlertBox automatically switches to using ID 3.
Text
````
AlertText is the text that is displayed in the Dynamic Alert. Text is automatically split into multiple lines by using word-wrap if necessary. AlertBox adjusts the box’s width to make the length of multiple lines as similar as possible. A Carriage Return (ASCII code $0D) can be used within the text to start a new line. You can use the ReturnKey constant to make your program more readable. This lets you form an alert box with multiple lines of text by using a single line of source code in your program.
A Dynamic Alert’s text is left-aligned unless it has no buttons, in which case the text is centered.
Buttons
```````
AlertCode specifies the button layout that appears in the Dynamic Alert, as well as the default button. The default button is outlined with a border and is automatically selected if the user presses the Return or Enter key. Nine common button combinations have been defined for you as constants. Examples of these combinations are provided later. Later in this manual, you will be shown how to define your own custom button combinations.
NoYesCanAlert=32243; {Yes/No + Cancel (No default) }
Custom Button Combinations
``````````````````````````
AlertCode is a number that specifies the Dynamic Alert’s button combination. Up to three of the following seven button names can be used in a Dynamic Alert Box. Your application can rename any of these buttons by using the AlertButtonName procedure.
CONST {Dynamic Alert buttons }
OkAltBut =1; {OK }
CanAltBut =2; {Cancel }
YesAltBut =3; {Yes }
NoAltBut =4; {No }
ContAltBut=5; {Continue }
SkipAltBut=6; {Skip }
QuitAltBut=7; {Quit }
The AlertCode is a long integer whose value is broken into 5 single-digit numbers, each of which specifies something about the button combination:
(1) Number of buttons displayed in the alert [0 to 3]
/
/ (2) Default button position [1 to 3, from right to left]. 0 if no
| / default button
| /
|/ (3) 1st button name [from 1 to 7, rightmost button]. 0 if no
|| / button in this position.
|| /
||/ (4) 2nd button name [from 1 to 7, second from right]. 0 if no
||| / button in this position.
||| /
|||/ (5) 3rd button name [from 1 to 7, third from right]. 0 if no
|||| | button in this position.
|||| /
|||| /
||||/
33243 AlertCode means: 3 buttons in the alert
3rd button from right is the default
button #2 (Cancel) is 1st button from right
button #4 (No) is 2nd button from right
button # 3 (Yes) is 3rd button from right
(the default)
Single button alerts have the button centered between the left and right side of the alert box. Two button alerts have their buttons placed side by side in the bottom right corner of the alert. Three button alerts have the first button placed on the bottom right side of the box, and the next two are paired off further to the left.
If the AlertCode is negative, the Dynamic Alert doesn’t beep when displayed. We strongly recommend that you define your own custom alert codes as constants, then use those constants in your application to make your source code more readable.
Function’s Value
````````````````
The AlertBox function returns with a value that indicates which button was clicked by the user. If AlertBox displayed no buttons, it returns with a value of 1.
CONST {Dynamic Alert buttons }
OkAltBut =1; {OK }
CanAltBut =2; {Cancel }
YesAltBut =3; {Yes }
NoAltBut =4; {No }
ContAltBut=5; {Continue }
SkipAltBut=6; {Skip }
QuitAltBut=7; {Quit }
Advanced Techniques
```````````````````
If your application uses a lot of Alerts, or you want to make as efficient use of memory as possible, you can store all the alerts’ messages as string resources and write your own function that accepts a string resource ID from the calling application, loads the string resource and hands it off to the AlertBox routine.
If you want to get even more advanced, you can add some extra data bytes to the end of your string resource, representing the icon number and button combination. Your application would call your alert function and provide it with a string resource ID. Your alert function would then load the string resource, read the data bytes and parse them into the theIcon and AlertCode parameters for the AlertBox function. By using this concept, you could process an alert with a call that looks like the following:
UserButton := MyAlert(501);
The number 501 would be your string resource ID, and UserButton would return the button that was selected by the user. You still have the advantage of using a Dynamic Alert, and you can enjoy even greater simplicity.
Note: It is possible for your application to call AlertBox when none of
its windows are active. An example of this occurs when running
the Finder under System 6 or prior: [1] user enters text in an
editing field on window “a”, [2] user opens a desk accessory,
[3] user clicks on another window (“b”) belonging to your
application, [4] your application determines that the user cannot
activate window “b” until the field in window “a” is corrected, so
it displays a Dynamic Alert stating so.
Whenever a Dynamic Alert is called, it automatically insures
that the front most window belonging to your application is active
before the alert is displayed.
Also see the AlertButtonName procedure to rename the buttons that appear in Dynamic Alerts.
Tools Plus provides seven different button titles that may be used in various combinations on dynamic alert boxes. Although button titles and button number constants are provided for only seven buttons (as detailed in AlertBox), a total of nine buttons are available for use.
Button specifies the button number (from 1 to 9) that is affected.
Title specified the button’s title that will appear on all subsequent Dynamic Alerts. The title may be up to 9 characters long. The size of the buttons on a dynamic alert box does not change to accommodate longer titles. The specified title stays in effect until it is explicitly changed by your application. If a null string is provided, the button resumes its default title.
Your application can rename any or all the button titles as required, but keep in mind that the constants defined for the AlertCode and buttons will not work correctly because buttons have been renamed.
Draw an icon (cicn, icl8, icl4, ICN#, or ICON) and optionally make it appear selected (darkened) or disabled (grayed).
pascal void DrawIcon (int theIcon, int left, int top,
Boolean EnabledFlag, Boolean SelectedFlag);
procedure DrawIcon(theIcon, left, top: INTEGER;
EnabledFlag, SelectedFlag: BOOLEAN);
TheIcon is the icon ID that is displayed.
Left and top define the top left-hand corner in the current window’s local co-ordinates where the icon is drawn.
The EnabledFlag indicates if the icon is drawn as enabled or not. An enabled icon is displayed normally, whereas a disabled icon is dimmed or “grayed out.” The two constants that can be used for this flag are enabled and disabled. In nearly all cases, you will want to draw the icon as enabled. If you were to superimpose the icon with a zone from a cursor table (to make it a click-sensitive area and behave like a button), you may want to draw it as disabled to signify that it can’t be selected.
The SelectedFlag indicates if the icon is to be drawn as selected or not. An unselected icon is displayed normally, whereas a selected icon is darkened. The two constants that can be used for this flag are selected and notSelected. In nearly all cases, you will want to draw the icon as notSelected. If you were to superimpose the icon with a cursor table (to make it a click-sensitive area and behave like a button), you may want to draw it as selected.
Intelligent Icon Drawing
````````````````````````
The DrawIcon procedure is flexible in that it can draw color and black & white icons of various types under any conditions. It does so by using the most appropriate icon in an icon family (detailed below), depending on the Macintosh’s availability of color, the number of colors displayed, and whether the icon is selected, not selected, enabled, or disabled.
If your application runs on a Macintosh with multiple monitors, DrawIcon automatically draws the icon correctly, even if the icon straddles multiple screens. For this reason, DrawIcon must be placed outside any BeginUpdateScreen / EndUpdateScreen structures.
Icon Family
```````````
DrawIcon can draw any of the following icon types:
cicn variable size 8-bit color icon with a monochrome (1-bit)
equivalent
icl8 32x32 pixel 8-bit color icon used primarily by the Finder as
your application’s icon
icl4 32x32 pixel 4-bit color icon used primarily by the Finder as
your application’s icon
ICN# 32x32 pixel monochrome (1-bit) icon used primarily by the
Finder as your application’s icon
ICON 32x32 pixel monochrome (1-bit) icon, the first official
Macintosh icon
When a specific icon ID is shared by two or more of the icon types listed above, those related icons are called an “icon family.” The simplest example of an icon family is found in the bundle (BNDL) resource in almost all Macintosh applications. The bundle resource, usually just called a bundle, is an organization of icons used by the Finder to display your application (and its related documents) on the desk top and in folders. The icon family with an ID of 128 is usually the icon that depicts your application, where icl8 is the 8-bit icon, icl4 is the 4-bit icon, and ICN# is the 1-bit icon.
DrawIcon makes use of icon families to display the best available icon. You can create and edit icons with a resource editor such as Apple’s ResEdit. When you create icons, remember to use ID numbers 128 or higher. The rest are reserved numbers.
Icon Selection
``````````````
When you specify an icon ID, DrawIcon selects an appropriate icon from the available icon family based on [1] whether or not the Macintosh has Color QuickDraw, [2] the number of colors available on the screen, and [3] whether the icon is selected or not. If Color QuickDraw is not available on the Macintosh running your application (Macintosh 512KE and Macintosh Plus only), or if your application has chosen not to use Color QuickDraw when executing the InitToolsPlus routine, DrawIcon will behave as though you are using a monochrome (black and white) monitor.
When selecting an appropriate icon from the icon family (as depicted in the table below), DrawIcon first determines the number of colors available on the screen. It then checks if the icon is selected or not. Once these two criteria have been determined, DrawIcon tries to find the optimum icon type in the icon family. If the optimum icon type is not available, DrawIcon descends to the second best choice, and so on down the list. DrawIcon will use icons intended for a lesser variety of colors (i.e. from 256 to 16) if an appropriate icon isn’t available to take advantage of all the colors the screen has to offer.
Screen Depth Available --Icon Selection Order--
(in bits) Colors Not Selected Selected
```````````` ````````` ```````````` ````````
8 (or more) 256 (or more) icl8 icl8
cicn cicn
4 16 icl4
2 4 ICN# ICN#
ICON ICON
cicn† cicn†
1 black & white ICN# ICN#
ICON ICON
cicn† cicn†
†Black and white portion only. Available on Macintosh SE/30 or higher
(Macintoshes with Color QuickDraw)
If, for example, your application is running on an 8-bit monitor and it is trying to display a selected icon with an ID of 130, DrawIcon will always look for icon types whose ID is 130, and will first try to display an icl8. If an icl8 can’t be found, it will try to find a cicn. If neither of those icons can be found, DrawIcon will continue down the list to the icons best suited for a 4-bit monitor. Since there aren’t any in the “selected” column, it will descend again to 2-bit monitors, where it will try to find ICN#, ICON and cicn icon types.
Drawing the Icon, Selecting, Disabling, and Masking
All icon types are created by drawing within a limited square, such as the 32x32 bit ICON. When the icon is displayed by DrawIcon, the icon’s image and the background within the boundaries of the square are drawn on the window. You can liken this process to using MacPaint and selecting the image by using the frame selection tool (not the lasso), then copying that image and pasting it on the destination window. As you will notice, the background is also pasted.
Selecting the icon darkens it when using color or gray-scale, except for icl4 icons which can’t be darkened (in which case a substitute monochrome icon is used and darkened). On black and white monitors, the icon image is inverted (black turns to white and white turns to black).
Disabling the icon overlays a “gray” pattern using a patBic transfer mode. This has the effect of removing alternating pixel to make the icon appear “grayed out.”
Each of these processes, drawing, selecting, and disabling, are done using the icon’s bounding square. If you want to limit the process to a smaller area, say, for example, to an area that is identical to an oddly shaped icon image, you can incorporate an icon mask. All drawing, selecting and disabling is performed only within the area defined by the icon mask. The cicn and ICN# icons both have integrated masks. If you use an icl8 or icl4 icon, also include an ICN# icon with the same ID, and DrawIcon will use its mask.
Creating Your Own Icons
```````````````````````
You can create your own icons using a resource editor, such as Apple’s ResEdit. When creating icl8 icons with ResEdit, you have a choice of two pallets: “Apple icon colors” or “Standard 256 colors.” If your icon is going to be drawn as selected, use only the Apple icon colors, since they will guarantee that your icon can be darkened properly. Note that icons that are displayed as both selected and disabled are usually difficult to read, since simultaneously darkening and grayed out often makes the image illegible.
You can also replace the system’s standard Stop, Note, and Warning icons with your own customized icons, simply by creating icons with the same IDs and including them in your application.
Warning: DrawIcon must be called outside a BeginUpdateScreen /
Determine what version of the System file is being used.
pascal double SystemVersion(void);
function SystemVersion: EXTENDED;
SystemVersion determines the version of the System file being used by your application (located on your startup disk). The System file’s version is expressed as three numeric components separated by periods (i.e. 7.0.1). Because a floating-point number has a single decimal, the second period is omited to present the decimal equivalent of 7.01.
Because this routine’s source code is compiled as part of your application (it can be found in the ToolsPlus.c file for C programmers, and the ToolsPlus.p interface file for Pascal programmers), it is compiled according to your project’s compiler settings for 680x0 processor optimization and/or math co-processor optimization. Therefore, SystemVersion returns a floating-point number that can be compared to constants in your source code, such as the following example:
Give some time to periodic tasks, such as flashing insertion points or displayed clocks.
pascal void SystemTasks(void);
procedure SystemTasks;
The SystemTasks routine performs two important functions: [1] it calls Macintosh toolbox’s SystemTask procedure (with no “s” at the end) which keeps desk accessories and periodic processes running, and [2] it calls TEIdle which keeps the insertion point in the active editing field flashing. SystemTasks is called automatically from within the PollSystem function.
Your application should ensure that PollSystem and/or SystemTasks are called at least every 1/60th of a second to keep things running smoothly.
ClockTicks specifies the time that is to be waited in sixtieths of a second, or clock ticks. This procedure calls SystemTask to ensure that periodic processes continue to function. The Wait procedure returns to the calling application after the specified number of clock ticks have transpired. If the number is less than or equal to zero, Wait returns immediately.
One example of using this procedure is when an application is first launched. After initializing Tools Plus, your application may decide to display an identification window that tells the user about the program and version number. While the window is displayed, your application can open files and obtain resources. You may decide to display the window for no less than 3 seconds, in which case you would first obtain the current number of ticks since startup from the TickCount function, display the identification window, then perform your other duties. When these tasks are completed, call TickCount again to determine how much time has transpired, then use Wait to delay for 180 ticks (3 seconds x 60 ticks), less the number of ticks that have passed since the window was first opened.
Warning: Use Wait judicially because events will still be accumulating
in the event queue while your application is waiting, and older
events may be lost. Also, other applications won’t be getting
any processing time while your application is waiting.
The drawing of “zoom lines” creates an illusion of transition between two objects. A good example of zoom line use is in the Finder. Whenever a document, application, or disk is opened, zoom lines expand from the object. This creates an illusion that the object is opening. Zoom lines also create an apparent screen depth, since they make an object appear to zoom towards the user when it is opening, and zoom back down onto the screen when it closes. This process is called “zooming in” or “zooming out.”
Another type of zoom lines is available, and that is “zooming across.” This involves a single object’s transition from one shape to another. An example of zooming across is when a window’s “zoom box” is clicked. The window changes from a user state to a standard state (or vice versa). When zooming across, the zoom lines move at a constant rate from the old co-ordinates to the new. Because no acceleration or deceleration occurs, screen depth appears to be constant.
OldRect and NewRect specify the original and destination rectangles in the screen’s global co-ordinates. Transition always occurs starting at OldRect and ending at NewRect, regardless if you are zooming in, zooming out, or zooming across.
ZoomType specifies the type of zoom operation being performed. The constants for this are: ZoomIn, ZoomOut and ZoomAcross.
CONST {Zoom Types }
ZoomIn =-1; {zoom down to an object }
ZoomOut =1; {zoom up from an object }
ZoomAcross=0; {transition from one object to another }
DisplayRect is the display rectangle in the current window’s local co-ordinates.
Percent is the percentage of the thermometer that is completed (i.e. .7 means 70% complete).
DrawThermometer draws the standard Macintosh progress thermometer, such as the one seen in the Finder when a file is being copied or duplicated. The thermometer is drawn according to the system that your Macintosh is running, and the settings of the monitor(s) on which the thermometer is displayed. The thermometer will always be similar to the one seen in the Finder.
Note: Even though DrawThermometer draws the thermometer very quickly, it
may not be fast enough for applications that perform many
thousands or even millions of operations during the thermometer’s
progression. In that case, use the toolbox’s TickCount function
to time calls to DrawThermometer at a less frequent rate.
Warning: DrawThermometer must be called outside a BeginUpdateScreen /